package com.crpc.core.proxy.handler;

import com.crpc.common.constant.MessageFormatConstant;
import com.crpc.core.compress.Compressor;
import com.crpc.core.compress.CompressorFactory;
import com.crpc.core.serialize.Serializer;
import com.crpc.core.serialize.SerializerFactory;
import com.crpc.core.transport.message.CrpcRequest;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j;

import static com.crpc.common.constant.MessageFormatConstant.*;

/**
 * <pre>
 *     0    1    2    3    4   5    6    7    8    9    10   11   12   13   14   15   16  17    18   19   20   21   22    23   24   25   26   27   28   29   30
 *     +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 *     /        magic      /ver / head len/  full length      / qt / ser/com /            requestId                  /       timeStamp                       /
 *     +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 *     /                                                                                                             /                                       /
 *     /                                  body                                                                       /                                       /
 *     /                                                                                                             /                                       /
 *     +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 * </pre>
 * <p>
 * 4b magic 魔数值 类似于鉴定标志-> crpc.getBytes()
 * 1b version 版本
 * 2b header length 头部长度
 * 4b full length 总的报文长度
 * 1b requestType
 * 1b serialize
 * 1b compress
 * 8b requestId
 * <p>
 * body
 *
 * @author wzy
 * @version 1.0
 * @description: 出栈时第一个经过的处理器
 * @date 2023/9/26 15:03
 */
@Slf4j
public class CrpcRequestEncoder extends MessageToByteEncoder<CrpcRequest> {
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, CrpcRequest crpcRequest, ByteBuf byteBuf) throws Exception {

        //魔数
        byteBuf.writeBytes(MAGIC);
        //版本号
        byteBuf.writeByte(MessageFormatConstant.VERSION);
        //2个字节头部长度
        byteBuf.writeShort(MessageFormatConstant.HEADER_LENGTH);
        //body长度
        byteBuf.writerIndex(byteBuf.writerIndex() + MessageFormatConstant.FULL_FIELD_Length);
        //三个类型,请求类型,序列化类型,压缩类型
        byteBuf.writeByte(crpcRequest.getRequestType());
        byteBuf.writeByte(crpcRequest.getSerializeType());
        byteBuf.writeByte(crpcRequest.getCompressType());
        //请求id
        byteBuf.writeLong(crpcRequest.getRequestId());
        byteBuf.writeLong(crpcRequest.getTimeStamp());
        //body内容
        //根据配置的序列化方式进行序列化
        Serializer serializer = SerializerFactory.getSerializer(crpcRequest.getSerializeType()).getSerializer();
        byte[] bodyBytesBefore = serializer.serialize(crpcRequest.getRequestPayLoad());
        byte[] bodyBytesAfter = null;
        int before = 0;
        int after = 0;
        //根据配置的压缩方式进行压缩
        if (bodyBytesBefore != null && bodyBytesBefore.length != 0) {
            before = bodyBytesBefore.length;
            Compressor compressor = CompressorFactory.getCompressor(crpcRequest.getCompressType()).getCompressor();
            bodyBytesAfter = compressor.compress(bodyBytesBefore);
            after = bodyBytesAfter.length;
        }
        if (bodyBytesAfter != null) {
            byteBuf.writeBytes(bodyBytesAfter);
        }
        int bodyLength = bodyBytesAfter == null ? 0 : bodyBytesAfter.length;
        //保存当前写指针的位置
        int writerIndex = byteBuf.writerIndex();
        byteBuf.writerIndex(MAGIC.length + VERSION_LENGTH + HEADER_FIELD_LENGTH);
        byteBuf.writeInt(MessageFormatConstant.HEADER_LENGTH + bodyLength);
        //指针归位
        byteBuf.writerIndex(writerIndex);
        log.info("请求：{}，已经在客户端完成请求的编码，压缩前的长度：{}，压缩后的长度：{}", crpcRequest.getRequestId(), before, after);
    }
}
